<?php
    /**
     * MySQL分库分表
     * User: guoyu
     * Date: 14-8-12
     * Time: 下午3:16
     */

    namespace App\Model\Database;

    class Config
    {
        public $dsn;
        public $user;
        public $password;
        /**
         * @var string 分库分表后得到的数据库名
         */
        public $dbname;
        /**
         * @var string 分库分表后得到的表名
         */
        public $table;

        /**
         * @var array MySQL 配置数组
         */
        private static $config;

        /**
         * @var string 配置文件路径
         */
        private static $configFile = 'mysql.php';

        public function __construct($dbname, $table, $id = 0)
        {
            if (is_null(static::$config)) {
                $config = include(static::$configFile);
                static::$config = $config;
            }

            $config = static::$config;
            if (isset($config['shared']) && isset($config['shared'][$dbname])) {
                $dbconfig = $config['shared'][$dbname];
                $id = is_numeric($id) ? (int)$id : crc32($id);
                $database_id = ($id / $dbconfig['database_split'][0]) % $dbconfig['database_split'][1];
                $table_id = ($id / $dbconfig['table_split'][0]) % $dbconfig['table_split'][1];

                foreach ($dbconfig['host'] as $key => $conf) {
                    list($from, $to) = explode('-', $key);
                    if ($from <= $database_id && $database_id <= $to) {
                        $the_config = $conf;
                    }
                }

                $this->dbname = $dbname . '_' . $database_id;
                $this->table = $table . '_' . $table_id;
            } else {
                $this->dbname = $dbname;
                $this->table = $table;
                $the_config = $config['db'][$dbname];
            }
            $c = $the_config;
            if (isset($c['unix_socket']) && $c['unix_socket']) {
                $this->dsn = sprintf('mysql:dbname=%s;unix_socket=%s', $this->dbname, $c['unix_socket']);
            } else {
                $this->dsn = sprintf('mysql:dbname=%s;host=%s;port=%s', $this->dbname, $c['host'], $c['port']);
            }
            $this->user = $c['user'];
            $this->password = $c['password'];
        }

    }
    ?>

    Config 类就做一个事情，根据配置文件，去拿到对应的库和表的链接配置，然后客户可以根据 dsn 去链接对应的数据库。对应的配置文件如下：

    [php] view plaincopyprint?在CODE上查看代码片派生到我的代码片

    <?php
    /**
     * User: guoyu
     * Date: 14-8-6
     * Time: 上午11:19
     */

    $default = array(
        'unix_socket' => null,
        'host' => 'localhost',
        'port' => '3306',
        'user' => 'root',
        'password' => '',
    );

    $config = array(
        // 不进行分库分表的数据库
        'db' => array(
            'my_site' => $default,
        ),
        // 分库分表
        'shared' => array(
            'user' => array(
                'host' => array(
                    /**
                     * 编号为 0 到 10 的库使用的链接配置
                     */
                    '0-10' => $default,
                    /**
                     * 编号为 11 到 28 的库使用的链接配置
                     */
                    '11-28' => $default,
                    /**
                     * 编号为 29 到 99 的库使用的链接配置
                     */
                    '29-99' => $default,

                ),

                // 分库分表规则
                /**
                 * 下面的配置对应百库百表
                 * 如果根据 uid 进行分表，假设 uid 为 543234678，对应的库表为：
                 *  (543234678 / 1) % 100 = 78 为编号为 78 的库
                 *  (543234678 / 100) % 100 = 46 为编号为 46 的表
                 */
                'database_split' => array(1, 100),
                'table_split' => array(100, 100),
            ),
        ),
    );


    return $config;
 ?>

给出一个使用这个分库分表的例子：

[php] view plaincopyprint?在CODE上查看代码片派生到我的代码片

    <?php
    /**
     * User: guoyu
     * Date: 14-8-6
     * Time: 上午10:23
     */

    namespace App\Model;

    use App\Model\Database\Config;
    use \PDO;

    abstract class Model
    {
        /**
         * @var Config
         */
        public $config;

        /**
         * @var PDO
         */
        public $connection;

        protected $dbnamePrefix;
        protected $tablePrefix;

        /**
         * @var string 分库分表后对应的表
         */
        protected $table;

        public function __construct($id)
        {
            $this->config = new Config($this->dbnamePrefix, $this->tablePrefix, $id);
            $this->connection = new Pdo($this->config->dsn, $this->config->user, $this->config->password);
            $this->table = $this->config->table;
        }

        public function update(array $data, array $where = array())
        {

        }

        public function select(array $where)
        {

        }

        public function insert(array $data)
        {

        }

        public function query($sql)
        {
            return $this->connection->query($sql);
        }
    }
?>
下面这个例子展示了如何使用上述的 Model 类：

<?php
/**
 * User: guoyu
 * Date: 14-8-12
 * Time: 下午4:06
 */

require 'Config.php';
require 'Model.php';

//use App\Model\Model;

class User extends Model
{
    protected $dbnamePrefix = 'user';
    protected $tablePrefix = 'userinfo';
}

$user = new User(4455345345);

print_r($user);
?>